package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.heima.aliyun.GreenImageScan;
import com.heima.aliyun.GreenTextScan;
import com.heima.common.constants.rabbit.RabbitArticlePublishConstants;
import com.heima.common.constants.wemedia.WemediaConstants;
import com.heima.common.exception.CustomizeExceptionBuilder;
import com.heima.feign.clients.AdminClient;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.service.IWmNewsAutoScanService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Correlation;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.postprocessor.MessagePostProcessorUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@Slf4j
public class WmNewsAutoScanService implements IWmNewsAutoScanService {

    @Autowired
    private WmNewsMapper wmNewsMapper;
    @Autowired
    private AdminClient adminClient;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 自动内容审核实现
     * @param newsId    自媒体文章 id
     */
    @Override
    public void autoScanWmNews(Integer newsId) {
        log.info("文章自动审核的方法被调用，当前审核的文章 id 为: {}", newsId);
        //1.校验参数
            //1.1校验文章 id
        if(newsId == null){
            log.error("文章自动审核失败，失败原因: {}", "文章 id 不存在");
            CustomizeExceptionBuilder.builder(AppHttpCodeEnum.PARAM_INVALID, "文章 id 不能为空");
        }
            //1.2校验文章是否是脏数据
        WmNews wmNews = wmNewsMapper.selectById(newsId);
        if(wmNews == null){
            log.error("文章自动审核失败，失败原因: {}", "待审核的文章不存在");
            CustomizeExceptionBuilder.builder(AppHttpCodeEnum.DATA_NOT_EXIST, "待审核文章不存在");
        }
            //1.3校验文章状态
        if(!WemediaConstants.WM_NEWS_SUMMIT_STATUS.equals(wmNews.getStatus())){
            log.error("文章自动审核失败，失败原因: {}", "待审核文章的状态为" + wmNews.getStatus());
            CustomizeExceptionBuilder.builder(AppHttpCodeEnum.DATA_NOT_ALLOW, "待审核文章的状态不为 0");
        }
        //2.执行自动审核
        Map<String, Object> textAndImageResult =  handlerTextAndImages(wmNews);
            //2.1敏感词过滤
        boolean isSensitiveFilter = handlerSensitive(wmNews, (String)textAndImageResult.get("text"));
        if(!isSensitiveFilter) return;
        log.info("平台敏感词审核已通过");
            //2.2接入阿里云内容审核接口 - 文本反垃圾检测
        boolean isTextScan = handlerTextScan(wmNews, (String)textAndImageResult.get("text"));
        if(!isTextScan)return;
        log.info("阿里云文本内容审核已通过");
        //2.3接入阿里云内容审核接口 - 图片审核
        boolean isImageScan = handlerImageScan(wmNews, (List<String>)textAndImageResult.get("image"));
        if(!isImageScan) return;
        log.info("阿里云图片内容审核已通过");
        //3.文章全部审核通过，修改文章的状态为 8
        updateWmNews(wmNews, WmNews.Status.SUCCESS.getCode(), null);
        //4.定时发布文章
        timedPublishArticle(wmNews);
    }

    /**
     * 生产者生产消息 - 定时文章发布
     * @param wmNews
     */
    private void timedPublishArticle(WmNews wmNews) {
        //1.计算 WmNews 发布时间
        long publish = wmNews.getPublishTime().getTime();
        long now = new Date().getTime();
        long ttl = publish - now <= 0 ? 0 : publish - now;
        //2.发送异步消息
        rabbitTemplate.convertAndSend(RabbitArticlePublishConstants.ARTICLE_PUBLISH_EXCHANGE,
                RabbitArticlePublishConstants.ARTICLE_PUBLISH_ROUTING_KEY,
                wmNews.getId(),
                new MessagePostProcessor() {
                    @Override
                    public Message postProcessMessage(Message message) throws AmqpException {
                        message.getMessageProperties().setExpiration(String.valueOf(0));
                        return message;
                    }
                });
        log.info("ApArticle 定时发布消息投递成功，WmNews 信息: {}, 延时时长: {}", wmNews, ttl + "ms");
    }

    @Autowired
    private GreenImageScan greenImageScan;

    /**
     * 接入阿里云图片内容审核
     * @param wmNews
     * @param image
     * @return
     */
    private boolean handlerImageScan(WmNews wmNews, List<String> image) {
        boolean flag = true;
        try {
            Map map = greenImageScan.imageUrlScan(image);
            if("block".equalsIgnoreCase((String) map.get("suggestion"))){
                updateWmNews(wmNews, WmNews.Status.FAIL.getCode(), "文章中有违规图片存在，审核失败");
                flag = false;
            }
            if("review".equalsIgnoreCase((String) map.get("suggestion"))){
                updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(),null);
                flag = false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("接入阿里云图片内容审核接口失败，失败原因: {}", e.getMessage());
            flag = false;
        }
        return flag;
    }

    @Autowired
    private GreenTextScan greenTextScan;

    /**
     * 接入阿里云文本内容审核接口
     * @param wmNews
     * @param text
     * @return
     */
    private boolean handlerTextScan(WmNews wmNews, String text) {
        boolean flag = true;
        try {
            Map map = greenTextScan.greenTextScan(text);
            if("block".equalsIgnoreCase((String) map.get("suggestion"))){
                updateWmNews(wmNews,WmNews.Status.FAIL.getCode(), "文本中存在违规内容，审核失败");
                flag = false;
            }
            if("review".equalsIgnoreCase((String) map.get("suggestion"))){
                updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), null);
                flag = false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("接入阿里云文本内容审核失败，失败原因: {}", e.getMessage());
            updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), null);
            flag = false;
        }
        return flag;
    }

    /**
     * 敏感词检测
     * @param wmNews
     * @param text
     * @return
     */
    private boolean handlerSensitive(WmNews wmNews, String text) {
        boolean flag = true;
        //1.查询敏感词集合 (feign 远程调用)
        ResponseResult<List<String>> responseResult = adminClient.findAllSensitives();
            //1.1判断远程调用没有发生熔断降级
        if(responseResult.getCode().intValue() != 0){
            CustomizeExceptionBuilder.builder(AppHttpCodeEnum.REMOTE_SERVER_ERROR, responseResult.getErrorMessage());
        }
        List<String> sensitives = responseResult.getData();
        //2对文章文本进行铭感词过滤
        SensitiveWordUtil.initMap(sensitives);
        Map<String, Integer> sensitiveFrequency = SensitiveWordUtil.matchWords(text);
        if(sensitiveFrequency != null && sensitiveFrequency.size() > 0){
            /*修改自媒体文章的状态：【自媒体文章】 【状态】 【审核失败理由】*/
            updateWmNews(wmNews, WmNews.Status.FAIL.getCode(), "文本中包含敏感词: " + sensitiveFrequency);
            flag = false;
        }
        return flag;
    }

    /**
     * 修改自媒体文章的状态
     * @param wmNews
     * @param statusCode
     * @param reason
     */
    private void updateWmNews(WmNews wmNews, Short statusCode, String reason) {
        wmNews.setStatus(statusCode);
        wmNews.setReason(reason);
        wmNewsMapper.updateById(wmNews);
    }

    @Value("${file.oss.web-site}")
    private String webSite;

    /**
     * 解析文本和图片数据
     * @param wmNews
     * @return
     */
    private Map<String, Object> handlerTextAndImages(WmNews wmNews) {
        String content = wmNews.getContent();
        List<Map> contentData = JSONArray.parseArray(content, Map.class);
        //1.解析文本数据
        String newsText = contentData.stream().filter(map -> "text".equals(map.get("type")))
                .map(entry -> (String) entry.get("value"))
                .collect(Collectors.joining("_😀_"));
        newsText = newsText + "_😀_" + wmNews.getTitle();
        //2.解析图片数据
        List<String> newsImage = contentData.stream().filter(map -> "image".equals(map.get("type")))
                .map(entry -> (String) entry.get("value"))
                .collect(Collectors.toList());
        String newsCoverImageStr = wmNews.getImages();
        if(StringUtils.isNotBlank(newsCoverImageStr)){
            List<String> newsCoverImage = Arrays.stream(newsCoverImageStr.split(","))
                    .map(element -> webSite + element)
                    .collect(Collectors.toList());
            newsImage.addAll(newsCoverImage);
        }
        newsImage = newsImage.stream().distinct().collect(Collectors.toList());
        //封装结果
        Map<String, Object> textAndImageResult = new HashMap<>();
        textAndImageResult.put("text", newsText);
        textAndImageResult.put("image", newsImage);
        return textAndImageResult;
    }
}
